#include "uthread_struct.h"
#include "lista.h"
#include <stdlib.h>
#include <stdio.h>

/* Fila de Threads Aptas */
static listaThreads *filaAptos;

/* Fila de todas as threads criadas */
static listaThreads *filaTodasThreads;

/* Variável para alocar a thread em execução */
static tcb *threadAtual;

/**
* Função que inicializa as variáveis para a biblioteca uthread
* @return int 0 se obteve sucesso, senão retorna -1
*/
int uth_init(void){

    return 0;

 }

/**
*  Função que cria uma thread, colocando-a na fila de aptos
*  @return int (tid da thread criada).
*/
int uth_create(void * (*funcaoInicial)(void*), void * arg){

	/*Inicialização*/
	tcb *tcb1;
	tcb1 = alocarThread();
	tcb1->funcao = funcaoInicial;
	tcb1->arg = arg;
	//getcontext(&tcb1->contexto); //salva o contexto atual

    /*Insere Thread criada na fila de aptos*/
    filaAptos = inserir(filaAptos, tcb1);

    /*Insere Thread criada na fila de todas as threads*/
    filaTodasThreads = inserir(filaAptos, tcb1);

	return tcb1->id;
}

/**
*  Função que retira a thread que está executando e a envia para a fila de aptos
*  Pega o primeira thread da fila de aptos e executa
*/
int uth_yield(void){
    tcb *threadParaExecutar;
    /* Reinserir thread atual na lista de aptos */
    if (threadAtual == NULL) //se sim, quem estava em execução era a main!
        uth_create(NULL, NULL); //Se a thread que está saindo do estado executando
        //é a main e ainda não tinha sido criada uma estrutura para ela,
        //então ela deve ser criada nesse momento indo para o estado APTO pela primeira vez
        //printf("Nao ha thread na variavel de threadAtual!\n\n"); exit(0);

    else {
        threadAtual->estado = APTO_JA_EXECUTADO;
        getcontext(&threadAtual->contexto);
        filaAptos = inserir(filaAptos, threadAtual);
    }

    /* Executa a primeira thread da fila de aptos */
    threadParaExecutar = buscarPrimeiroElemento(filaAptos); //Busca 1o elemento da fila
    if (threadParaExecutar == NULL){ //se sim, não havia threads na fila de aptos
        //o que fazer aqui??  Este caso nunca acontece já que quando chamamos a função YELD
        //retiramos uma thread em execução e a colocamos na fila de APTO
        printf ("Nao havia threads na fila de aptos");
        return -1;
    } else {
        threadAtual = threadParaExecutar;
        eliminaPrimeiroElemento(filaAptos);  //atualiza a fila de aptos tirando a thread que foi para o estado executando
        if(threadParaExecutar->estado == APTO_NUNCA_EXECUTADO){
            threadParaExecutar->estado = EXECUTANDO;
            threadParaExecutar->funcao(*((int*)threadParaExecutar->arg));
        }
        else{
            printf("dando Set Context\n");
            imprimeThread(threadParaExecutar);
            //setcontext(&threadParaExecutar->contexto);
        }
        printf ("FUNCAO YIELD IMCOMPLETA, TERMINAR\n");
    }



return 0;
}


int uth_wait(int thr) { return 1; } //IMPLEMENTAR ESSA FUNÇÃO

